

const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
/**代码题一**/
{
    function myTimer(text) {
        const promise = new Promise((resolve, reject) => {
            setTimeout(function () {
                resolve(text)
            }, 10)
        })
        return promise
    }
    myTimer('hello ').then(res => {
        return myTimer(res + 'lagou ')
    }).then(res => {
        console.log(res + 'I ♥ you')
    })

}

/**代码题二**/
const cars = [{ name: 'Ferrari FF', horsepower: 660, dollar_value: 700000, in_stock: true },
{ name: 'Spyker c12 Zagato', horsepower: 650, dollar_value: 648000, in_stock: false },
{ name: 'Jaguar XKR-S', horsepower: 550, dollar_value: 132000, in_stock: false },
{ name: 'Audi R8', horsepower: 525, dollar_value: 114200, in_stock: false },
{ name: 'Aston Martin One-77', horsepower: 750, dollar_value: 1850000, in_stock: true },
{ name: 'Pagani Huayra', horsepower: 700, dollar_value: 1300000, in_stock: false },
]
//练习1 fp.flowRight()实现下面函数
/*let isLastInStock = function(cars){
     let last_cars =  fp.last(cars)
     return fp.prop('in_stock',last_cars)
}
*/
{
    const f = function (prop) {
        return fp.flowRight(fp.prop(prop), fp.last)
    }
    const getInstock = f('in_stock')
    console.log(getInstock(cars))  //输出false
}

//练习2 fp.flowRight() fp.prop() fp.first()获取第一个car的name
{
    const f = function (prop) {
        return fp.flowRight(fp.prop(prop), fp.first)
    }
    const getName = f('name')
    console.log(getName(cars))  //输出Ferrari FF

}
//练习3 使用帮助函数 _average 重构 averageDOLLARValue 使用组合函数方式实现
// let _average = function(xs){
//      return fp.reduce(fp.add,0,xs)
// }
// let averageDOLLARValue = function(cars){
//     let dollars_values = fp.map(function(car){
//         return car.dollar_value
//     },cars)
//     return _average(dollars_values)
// } 

{
    let _average = function (xs) {
        return fp.reduce(fp.add, 0, xs)
    }
    function mapArr(arr) {
        return fp.map(function (car) {
            return car.dollar_value
        }, cars)
    }
    let averageDOLLARValue = fp.flowRight(_average, mapArr)
    console.log(averageDOLLARValue(cars))
}
{
    //练习4 使用flowRight写一个sanitizeNames()函数，返回下划线连接的小写字母
    // ex:  sanitizeNames(['Hello World']) => ['hello_world']
    let arr = ['Hello World', 'La Gou', 'Are You Ok']
    let _underscore = fp.replace(/\W+/g, '_')
    const sanitizeNames = fp.flowRight(fp.map(_underscore), fp.map(fp.toLower))
    console.log(sanitizeNames(arr))  //输出  [ 'hello_world', 'la_gou', 'are_you_ok' ]

}
/**代码题三**/
{

    //练习1  使用fp.add(x,y)和fp.map(f,x)创建一个能让functor里的值增加的函数ex1
    let maybe = Maybe.of([1, 2, 3])
    let ex1 = (num) => {
        return maybe.map(function (value) {
            return fp.map((item) => fp.add(num, item), value)
        })
    }
    console.log(ex1(2)) // 数组加2  [3,4,5]

}
{

    //练习2  ex2函数 使用fp.first获取列表第一个元素
    let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
    let ex2 = () => {
        let first = ''
        xs.map(item => {
            first = fp.first(item)
            return item
        })
        return first
    }
    console.log(ex2())  //输出do
}
{
    //练习3  ex3函数 使用safeProp和fp.first找到user名字首字母
    let safeProp = fp.curry(function (x, o) {
        return Maybe.of(o[x])
    })
    let user = {
        name: 'Albert',
        id: 2
    }
    let ex3 = (userInfo, prop) => {
        return fp.flowRight(fp.first, () => safeProp(prop, userInfo)._value)()
    }
    console.log(ex3(user, 'name'))  //输出A
}
{
    //练习4  Maybe重写 ex4函数 不要有if
    //  let ex4 = function(n){
    //      if(n){
    //          return parseInt(n)
    //      }
    //  }
    let ex4 = function (n) {
        return Maybe.of(n).map(value => parseInt(value))._value
    }
    console.log(ex4(9.7)) //输出9


}






{
    //手写peomise
//1  promise是一个类 实例化这个类的时候传递一个函数，会被立即执行
//2  promise有三种状态 pending fulfilled rejected  一旦确定状态不可更改 pending->fulfilled  pending->rejected
//3  resolve和reject用来更改状态  resolve----->fulfilled  reject----->rejected
//4  then 方法判断状态  状态是成功调用成功函数 成功函数参数是成功的返回值  失败调用失败回调 失败成功函数参数是失败的原因
//5  resolve静态方法用来生成promise实例
//6  promise.all 接受数组，可以传递promise或者普通变量，promise等待返回结果，普通变量返回对应结构
//7  finally静态方法不管成功失败都会调用，返回
    
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    //promise源码 
    /* promise是一个类  */
    class myPromise {
        static resolve(value) {
            if (value instanceof myPromise) {
                return value
            } else {
                return new myPromise(resolve => resolve(value))
            }
        }
        static all(array) {
            let result = []
            let index = 0
            return new myPromise((resolve, reject) => {
                function addData(i, value) {
                    result[i] = value
                    index++
                    if (index === array.length) {
                        //所有promise执行完毕了返回最后的结果
                        resolve(result)
                    }

                }
                array.forEach((item, i) => {
                    if (item instanceof myPromise) {
                        //promise对象
                        item.then(value => addData(i, value), reason => reject(reason))
                    } else {
                        //普通值
                        addData(i, item)
                    }
                })

            })
        }
        constructor(fn) {
            try {
               // 实例化这个类的时候传递一个函数，会被立即执行
                fn(this.resolve, this.reject)  //立即执行promise的回调函数
            } catch (e) {
                //捕获错误
                this.reject(e)
            }

        }
        //promise 状态
        status = PENDING
        //成功的值
        value = undefined
        //失败的原因
        reason = undefined
        //成功回调
        successCallBack = []
        //失败回调
        failCallBack = []
        resolve = value => {
            if (this.status !== PENDING) return
            this.status = FULFILLED
            //保存成功的值
            this.value = value
            //判断成功回调是否存在，存在就调用
            this.successCallBack.length > 0 && this.successCallBack.forEach(item => item())
        }
        reject = errReason => {
            if (this.status !== PENDING) return
            this.status = REJECTED
            //保存失败的原因
            this.reason = errReason
            //判断失败回调是否存在，存在就调用
            this.failCallBack.length > 0 && this.failCallBack.forEach(item => item())
        }
        then = (successCallBack, failCallBack) => {
            //then是否传递了回调函数，没有默认返回一个resolve的结果
            successCallBack = successCallBack ? successCallBack : value => value
            failCallBack = failCallBack ? failCallBack : value => { throw value }
            //返回一个新的promise
            const promise = new myPromise((resolve, reject) => {
                //判断状态
                if (this.status === FULFILLED) {
                    setTimeout(() => { //添加异步回调防止获取promise的时候还没有值
                        try {
                            //传递成功的值
                            let x = successCallBack(this.value)
                            //判断x是promise对象还是普通值 
                            //如果是promise，查看promise返回的结果，决定调用resolve还是reject       
                            resolvePromise(promise, x, resolve, reject) //then链式调用
                        } catch (e) {
                            reject(e)
                        }

                    }, 0)

                } else if (this.status === REJECTED) {
                    //传递失败的原因
                    failCallBack(this.reason)
                    setTimeout(() => {
                        try {
                            //传递成功的值
                            let x = failCallBack(this.reason)
                            //判断x是promise对象还是普通值 
                            //如果是promise，查看promise返回的结果，决定调用resolve还是reject       
                            resolvePromise(promise, x, resolve, reject) //then链式调用
                        } catch (e) {
                            reject(e)
                        }

                    }, 0)

                } else {
                    //等待  存储回调
                    this.successCallBack.push(() => {
                        setTimeout(() => {
                            try {
                                //传递成功的值
                                let x = successCallBack(this.value)
                                //判断x是promise对象还是普通值 
                                //如果是promise，查看promise返回的结果，决定调用resolve还是reject       
                                resolvePromise(promise, x, resolve, reject) //then链式调用
                            } catch (e) {
                                reject(e)
                            }

                        }, 0)
                    })
                    this.failCallBack.push(() => {
                        setTimeout(() => {
                            try {
                                //传递成功的值
                                let x = failCallBack(this.reason)
                                //判断x是promise对象还是普通值 
                                //如果是promise，查看promise返回的结果，决定调用resolve还是reject       
                                resolvePromise(promise, x, resolve, reject) //then链式调用
                            } catch (e) {
                                reject(e)
                            }

                        }, 0)
                    })
                }
            })
            return promise
        }
        finally(callback) {
            //成功失败都会调用
            return this.then(value => {
                //promise状态改变后执行
                return myPromise.resolve(callback()).then(() => value)
            }, error => {
                return myPromise.resolve(callback()).then(() => { throw error })
            })
        }
        catch(failCallback) {
            //捕获失败
            return this.then(undefined, failCallback)
        }
    }
    function resolvePromise(promise, x, reslove, reject) {
        if (promise === x) {
            //传递了自身实例对象，引起死循环
            return reject(new Error('Chaining cycle detected for promise #<Promise>'))
        }
        if (x instanceof myPromise) {
            //传递promise,返回promise的结果
            x.then(reslove, reject)
        } else {
            //传递普通变量，返回对应数据
            reslove(x)
        }
    }
    new myPromise(function(resolve,reject){
         resolve(1)
    }).then(res=>{
         console.log(res)
    })
}